﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Controls;

namespace RoofusUIControls
{
    class HalfWayCalculator : DependencyObject
    {
        /// <summary>
        /// The result of our calculation
        /// </summary>
        public double Position
        {
            get { return (double)GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Position.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PositionProperty =
            DependencyProperty.Register("Position", typeof(double), typeof(HalfWayCalculator), new UIPropertyMetadata(0.0));


        /// <summary>
        /// The size of the object. We will return 1/2 this guy and some offset (perhaps)
        /// </summary>
        public double ObjectSize
        {
            get { return (double)GetValue(ObjectSizeProperty); }
            set { SetValue(ObjectSizeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ObjectSize.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ObjectSizeProperty =
            DependencyProperty.Register("ObjectSize", typeof(double), typeof(HalfWayCalculator),
            new UIPropertyMetadata(0.0, new PropertyChangedCallback(NumbersUpdated)));

        /// <summary>
        /// The object that we want to calc coordinates relative to (don't expect this to change dynamically!).
        /// </summary>
        public FrameworkElement Host { get; set; }

        /// <summary>
        /// Object that we need to go half way down.
        /// </summary>
        public Rectangle Object
        {
            get;
            set;
        }

        FrameworkElement _when_it_moves;
        /// <summary>
        /// Seated in a Canvas, watch for it to move.
        /// </summary>
        public FrameworkElement MoveMonitor { get {return _when_it_moves;}
            set
            {
                _when_it_moves = value;
                DependencyPropertyDescriptor dpd;
                if (UseHorizontalCoordinate)
                {
                    dpd = DependencyPropertyDescriptor.FromProperty(Canvas.LeftProperty, typeof(Canvas));
                }
                else
                {
                    dpd = DependencyPropertyDescriptor.FromProperty(Canvas.TopProperty, typeof(Canvas));
                }
                dpd.AddValueChanged(_when_it_moves, new EventHandler(MoveMonitorFired));
            }
        }

        private void MoveMonitorFired(object s, EventArgs e)
        {
            RecalcPosition();
        }

        /// <summary>
        /// If true, we look at width, otherwise the height
        /// </summary>
        public bool UseHorizontalCoordinate { get; set; }

        /// <summary>
        /// The size is changing, recalc.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="changes"></param>
        private static void NumbersUpdated(DependencyObject obj, DependencyPropertyChangedEventArgs changes)
        {
            HalfWayCalculator hw = obj as HalfWayCalculator;
            if (hw != null)
            {
                hw.RecalcPosition();
            }
        }

        /// <summary>
        /// Recalculate the various numbers.
        /// </summary>
        private void RecalcPosition()
        {
            Point p = new Point(0, 0);
            Point onscreen = Object.PointToScreen(p);
            Point inhost = Host.PointFromScreen(onscreen);

            if (UseHorizontalCoordinate)
            {
                Position = ObjectSize / 2.0 + inhost.X;
            }
            else
            {
                Position = ObjectSize / 2.0 + inhost.Y;
            }
        }


        private Binding _binding = null;
        /// <summary>
        /// Returns a binding to the position object
        /// </summary>
        public Binding PositionBinding
        {
            get
            {
                if (_binding == null)
                {
                    _binding = new Binding();
                    _binding.Path = new PropertyPath(HalfWayCalculator.PositionProperty);
                    _binding.Source = this;
                }
                return _binding;
            }
        }

        /// <summary>
        /// Short-cut to help with doing the binding.
        /// </summary>
        /// <param name="prop"></param>
        /// <param name="source_binding"></param>
        public void SetBinding(DependencyProperty prop, Binding source_binding)
        {
            BindingOperations.SetBinding(this, prop, source_binding);
        }
    }
}
